package com.spring.nio.core.event.listener;

import com.spring.nio.core.event.handler.WriteEventHandler;
import com.spring.nio.core.event.listener.event.ExceptionEvent;
import com.spring.nio.core.event.listener.event.constant.EventSourceTypeEnum;
import com.spring.nio.core.event.listener.event.constant.ExceptionEventTypeEnum;
import com.spring.nio.core.event.listener.event.model.EventSource;
import com.spring.nio.core.event.listener.event.model.ExceptionEventSource;
import com.spring.nio.core.event.listener.event.model.FileHandlerExceptionEventSource;
import com.spring.nio.core.event.listener.event.model.NioReadExceptionEventSource;
import com.spring.nio.core.exception.frame.ExceptionFrame;
import com.spring.nio.service.common.Response;
import com.spring.nio.service.protocol.response.file.TransportResponse;
import com.spring.nio.util.LocalTime;
import com.spring.nio.util.NioUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;

import java.io.IOException;
import java.net.SocketException;
import java.nio.channels.ClosedChannelException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: YSFY
 * @Date: 2020-11-21 12:07
 * @Pacage_name: com.spring.nio.core.event.listener
 * @Project_Name: nio-server
 * @Description: 异常事件监听器
 */
@Slf4j
public class ExceptionListener implements ApplicationListener<ExceptionEvent> {

    @Override
    public void onApplicationEvent(ExceptionEvent exceptionEvent) {
        // 具体事件源类型
        ExceptionEventSource exceptionEventSource = (ExceptionEventSource) exceptionEvent.getSource();

        // chat business exception
        if(exceptionEventSource.getExceptionEventTypeEnum().equals(ExceptionEventTypeEnum.CHAT_BUSINESS_HANDLER_EXCEPTION)) {

        }

        // file IO exception
        if(exceptionEventSource.getExceptionEventTypeEnum().equals(ExceptionEventTypeEnum.FILE_TRANSPORT_HANDLER_IO_EXCEPTION)) {
            if(exceptionEventSource instanceof FileHandlerExceptionEventSource) {
                ((FileHandlerExceptionEventSource) exceptionEventSource).getFileTransportTaskDto().setTaskStatus("EXCEPTION");
            }

            // 文件传输处理IO异常
            log.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ] ExceptionListener | --> 服务端异常信息 [{}] ", exceptionEventSource.getModule() + ", 具体为" + exceptionEventSource.getException().getMessage());
            // 是否发送异常信息
            if(exceptionEventSource.getIsSend()) {
                TransportResponse transportResponse = new TransportResponse();
                transportResponse.setCode("200");
                transportResponse.setFrameType(ExceptionFrame.FrameType.EXCEPTION.getBit());
                transportResponse.setOperate(ExceptionFrame.ExceptionOperateType.CLOSE_SOCKET.getOperateType());
                transportResponse.setMessage("[服务端异常信息] --> " + exceptionEventSource.getException().getMessage());
                WriteEventHandler.addSendData(transportResponse, exceptionEventSource.getSocketChannelContext());
            }
        }

        // nio read event Exception
        if(exceptionEventSource.getExceptionEventTypeEnum().equals(ExceptionEventTypeEnum.NIO_READ_EVENT_HANDLER)) {
            NioReadExceptionEventSource nioReadExceptionEventSource = (NioReadExceptionEventSource) exceptionEventSource;
            if(nioReadExceptionEventSource.getException() instanceof SocketException) {
                // Connection reset || Connection reset by peer:Socket write error || Broken pipe
            }

            if(nioReadExceptionEventSource.getException() instanceof ClosedChannelException) { // socketChanel 已经关闭依旧发生read
                log.warn("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ] ReadEventHandler | --> can not read data at a closed socketChannel}");
            }

            // 文件IO异常
            if(nioReadExceptionEventSource.getException() instanceof IOException) {
                log.error("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ] ReadEventHandler | --> 处理socketChannel读取数据产生I/O异常,异常原因为: ");
            }

            // 当前通道异常，取消通道对应的可选键
            NioUtil.closedAndRelease(nioReadExceptionEventSource.getSocketChannelContext(), nioReadExceptionEventSource.getIsLogout(), nioReadExceptionEventSource.getIsClearSingleFileUploadTask(), nioReadExceptionEventSource.getIsClearSingleFileDownloadTask());
        }
    }
}
